package com.vhall.component.service.interactive.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vhall.component.dao.account.AccountMapper;
import com.vhall.component.dao.interactive.DocumentsRoomMapper;
import com.vhall.component.entity.account.AccountEntity;
import com.vhall.component.entity.interactive.vo.*;
import com.vhall.component.entity.room.RoomDocumentsEntity;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.utils.BeanCopyUtil;
import com.vhall.component.service.interactive.DocumentsConsoleService;
import com.vhall.component.service.interactive.DocumentsRoomService;
import com.vhall.component.service.interactive.utils.Reader;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 文档控制台实现类
 *
 * @author shenqing
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DocumentsConsoleServiceImpl implements DocumentsConsoleService {

    private final DocumentsRoomService documentsRoomService;

    private final DocumentsRoomMapper documentsRoomMapper;

    private final RedisTemplate redisTemplate;
    /**
     * 上传文件名称长度限制
     */
    private static final int FILE_NAME_LENGTH_LIMIT = 90;
    /**
     * 上传文件页数限制
     */
    private static final int FILE_PAGE_NUM_LIMIT = 200;
    /**
     * 文档文件大小限制
     */
    private static final int DOCUMENT_SIZE_LIMIT = 1024 * 1024 * 100;
    /**
     * 上传文件限制类型数组
     */
    private static final String[] CHECK_TYPE = new String[]{"txt", "doc", "docx", "xls",
            "xlsx", "ppt", "pptx", "pdf", "jpeg", "jpg", "png", "bmp"};

    @Resource
    private AccountMapper accountMapper;

    @Override
    public Boolean consoleUpload(DocumentConsoleUploadReqVO reqVO) {

        //获取文件大小(单位:字节)
        checkDocumentUploadFile(reqVO);
        Token account = TokenThreadLocal.getToken();
        if (null == account) {
            throw new BusinessException(BizErrorCode.AUTH_LOGIN_NEEDS);
        }
        Integer accountId = account.getAccountId();
        DocumentUploadReqVO vo = new DocumentUploadReqVO();
        vo.setDocument(reqVO.getDocument());
        if (null != accountId) {
            vo.setAccountId(accountId);
        }
        DocumentUploadRsp upload = documentsRoomService.upload(vo);
        return Objects.nonNull(upload.getDocumentId());
    }

    /**
     * 检查上传文件
     *
     * @param reqVO 上传的文件参数
     */
    private void checkDocumentUploadFile(DocumentConsoleUploadReqVO reqVO) {
        if (reqVO.getDocument().isEmpty()) {
            throw new BusinessException(BizErrorCode.COMP_DOC_EMPTY);
        }
        MultipartFile document = reqVO.getDocument();
        long documentSize = document.getSize();
        log.info(MessageFormat.format("当前文件大小：【{0}】 【{1}】", documentSize, DOCUMENT_SIZE_LIMIT));
        if (documentSize >= DOCUMENT_SIZE_LIMIT) {
            throw new BusinessException(BizErrorCode.COMP_DOC_SIZE);
        }
        try {
            int filePageNum = Reader.getFilePageNum(document);

            if (filePageNum > FILE_PAGE_NUM_LIMIT) {
                throw new BusinessException(BizErrorCode.COMP_DOC_PAGE);
            }
        } catch (IOException e) {
            log.error("获取页数失败. :{}", e.getMessage());
        }
        String name = document.getOriginalFilename();
        assert name != null;
        //文档名称长度校验
        if (name.length() > FILE_NAME_LENGTH_LIMIT) {
            throw new BusinessException(BizErrorCode.BIZ_FILE_NAME_IS_TOO_LONG);
        }
        String ext = Objects.requireNonNull(FileUtil.extName(name)).toLowerCase();

        boolean contains = ArrayUtils.contains(CHECK_TYPE, ext);
        if (!contains) {
            throw new BusinessException(BizErrorCode.BIZ_TYPE_NOT_ALLOWED);
        }

    }

    @Override
    public DocumentDeleteRespVO delete(DocumentConsoleDeleteReqVO reqVO) {
        Token account = TokenThreadLocal.getToken();
        if (null == account) {
            throw new BusinessException(BizErrorCode.AUTH_LOGIN_NEEDS);
        }
        DocumentDeleteRespVO documentDeleteRespVO = new DocumentDeleteRespVO();
        int delCount = 0;
        List<String> documentList = new ArrayList<>();
        List<String> documentIds = Arrays.stream(reqVO.getDocumentIds().split(",")).collect(Collectors.toList());
        for (String documentId : documentIds) {
            final Double score = redisTemplate.opsForZSet().score(RedisKey.ROOM_DOC, documentId);
            if (StringUtils.isNotBlank(documentId) && score == null) {
                //判断当前文档是否正在演示中，非演示中可以删除
                DocumentDeleteReqVO vo = new DocumentDeleteReqVO();
                vo.setDocumentId(documentId.trim());
                documentsRoomService.delete(vo);
                delCount++;
            } else {
                documentList.add(documentId.trim());
            }
        }
        documentDeleteRespVO.setNotDelIds(documentList);
        documentDeleteRespVO.setDelCount(delCount);
        return documentDeleteRespVO;
    }

    @Override
    public DocumentListRspVO list(DocumentConsoleListReqVO reqVO) {
        Token account = TokenThreadLocal.getToken();
        if (null == account) {
            throw new BusinessException(BizErrorCode.AUTH_LOGIN_NEEDS);
        }
        LambdaQueryWrapper<RoomDocumentsEntity> wrappers = Wrappers.lambdaQuery();
        if (account.getRoleType() != 1){
            // 查询当前用户所在部门所有的文档
            AccountEntity accountEntity = accountMapper.selectById(account.getAccountId());
            LambdaQueryWrapper<AccountEntity> accountEntityLambdaQueryWrapper = Wrappers.lambdaQuery();
            accountEntityLambdaQueryWrapper.eq(AccountEntity::getOrgCode, accountEntity.getOrgCode());
            List<AccountEntity> accountEntities = accountMapper.selectList(accountEntityLambdaQueryWrapper);
            List<Integer> accountIdsOfOrg = accountEntities.stream().map(AccountEntity::getAccountId).collect(Collectors.toList());
            wrappers.in(RoomDocumentsEntity::getAccountId, accountIdsOfOrg);
        }

        if (!StringUtils.isBlank(reqVO.getKeyword())) {
            wrappers.like(RoomDocumentsEntity::getFileName, reqVO.getKeyword().trim());
        }
        wrappers.orderByDesc(RoomDocumentsEntity::getCreatedAt);
        Page<RoomDocumentsEntity> page = new Page<>(reqVO.getPage(), reqVO.getPageSize());
        page = documentsRoomMapper.selectPage(page, wrappers);

        List<RoomDocumentsEntity> records = page.getRecords();
        List<RoomDocumentsVO> roomDocumentsVoS = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(records)) {
            roomDocumentsVoS = BeanCopyUtil.batchCopy(records, RoomDocumentsVO::new);

            List<String> accountIdList = records.stream().map(RoomDocumentsEntity::getAccountId).collect(Collectors.toList());
            List<AccountEntity> accountEntitys = accountMapper.selectBatchIds(accountIdList);
            if (CollectionUtil.isNotEmpty(accountEntitys)) {
                Map<Integer, String> idNameMap = accountEntitys.stream().collect(Collectors.toMap(AccountEntity::getAccountId, AccountEntity::getUsername));
                roomDocumentsVoS.forEach(e -> e.setAccountName(idNameMap.get(Integer.valueOf(e.getAccountId()))));
            }

        }


        DocumentListRspVO resp = new DocumentListRspVO();
        resp.setCurrPage(reqVO.getPage());
        resp.setPageSize(reqVO.getPageSize());
        resp.setTotal(Integer.parseInt(String.valueOf(page.getTotal())));
        resp.setDetail(roomDocumentsVoS);
        return resp;
    }
}


